/// ===========================================================================
/// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
/// KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
/// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
/// PURPOSE.
/// ===========================================================================
/// 
/// Project:        BDC Wrapper
/// Author:         Leonid Lyublinski 
/// Date:           09/17/2008  Version:        1.0
///
/// ===========================================================================

using System;
using System.Xml;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Data;
using System.Runtime.InteropServices;
using System.Security;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Microsoft.Office.Server.ApplicationRegistry.Runtime;
using Microsoft.SharePoint.Portal.WebControls;
using SPWebControls = Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages.Communication;
using Microsoft.SharePoint;

using AspWebParts = System.Web.UI.WebControls.WebParts;
using MdModel = Microsoft.Office.Server.ApplicationRegistry.MetadataModel;
using SPWebParts = Microsoft.SharePoint.WebPartPages;

namespace MayaIntl.SharePoint.Portal.WebControls
{
    /// <summary>
    /// A wrapper web part that knows how to talk to BDC Data Lists
    /// </summary>
    /// <seealso cref="http://weblogs.asp.net/gunnarpeipman/archive/2007/11/29/how-to-connect-business-data-catalog-bdc-lists-to-other-sharepoint-lists.aspx"/>
    [Guid("183A2342-8976-4c4c-8FB0-6746FD50026A")]
    [CLSCompliant(false)]
    [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.Demand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
    [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
    [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Execution = true)]
    [System.Xml.Serialization.XmlRoot(Namespace = "MayaIntl.SharePoint.Portal.WebControls.BDCWrapper")]
    public class BDCWrapper : AspWebParts.WebPart, AspWebParts.IWebPartRow, SPWebParts.ITransformableFilterValues
    {
        #region Fields
        private DataRow _rowProvider;
        private DataTable _tableProvider;
        private MdModel.View _viewProvider;
        private bool _isConnectedAsConsumer;
        private string _providerName;
        private bool _isConnectedAsProvider;
        private string _consumerName;
        private string _persistedView;
        private string _userView;
        private bool _isConnectedAsFilterProvider;
        private string _filterConsumerName;
        private string _parameterName;
        private List<string> _selectedFields = null;

        string propertyName;
        string propertyValue;
        #endregion

        #region Properties
        [AspWebParts.Personalizable(AspWebParts.PersonalizationScope.Shared)]
        [System.ComponentModel.DefaultValue(null)]
        [AspWebParts.WebBrowsable(false)]
        public string PersistedView
        {
            get { return _persistedView; }
            set
            {
                _persistedView = value;
            }
        }

        public string UserView
        {
            get 
            {
                if (ViewState["UserView"] != null) return ViewState["UserView"].ToString();
                return _userView; 
            }
            set
            {
                _userView = value;
                ViewState["UserView"] = _userView;
            }
        } 
        #endregion

        #region CTOR
        /// <summary>
        /// Constructor of class. Let's initialize data table that 
        /// holds filter value.
        /// </summary>
        public BDCWrapper()
        {

        }
        #endregion

        #region Overrides
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);
            if (_isConnectedAsConsumer)
            {
                writer.Write(string.Format(Resource.CONNECTED_TO_PROVIDER_MSG, _providerName));
            } else {
                writer.Write(Resource.NOTCONNECTED_TO_PROVIDER);
            }
            writer.WriteBreak();
            if (_isConnectedAsProvider)
            {
                writer.Write(string.Format(Resource.CONNECTED_TO_CONSUMER_MSG, _consumerName));
            } else {
                writer.Write(Resource.NOTCONNECTED_TO_CONSUMER);
            }
            writer.WriteBreak();
            if (_isConnectedAsFilterProvider)
            {
                writer.Write(string.Format(Resource.CONNECTED_TO_FILTERCONSUMER_MSG));
            }
            else
            {
                writer.Write(Resource.NOTCONNECTED_TO_FILTERCONSUMER_MSG);
            }
            writer.WriteBreak(); 
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
        }
        #endregion

        #region Consumer members
        /// <summary>
        /// Connection point for Business Data Catalog Web Parts.
        /// </summary>
        /// <param name="provider">Connecting BDC provider.</param>
        /// <remarks>
        /// Keep the ID (currently Cons2193838) and don't delete it or
        /// you may face somenasty problems. You can always change 
        /// this ID.
        /// </remarks>
        [AspWebParts.ConnectionConsumer("BDC Entity", "BDCConsumer", AllowsMultipleConnections=false)]
        public void SetConnectionPoint(IEntityInstanceProvider provider)
        {
            try
            {
                // Method is called but there is no provider.
                if (provider == null) return;

                // Method is called but there is no selected entity.
                MdModel.Entity entProvider = provider.SelectedConsumerEntity;
                if (entProvider == null) return;
                _providerName = entProvider.Name;
                
                if (entProvider.HasSpecificFinder())
                {
                    _viewProvider = entProvider.GetSpecificFinderView();
                }
                else if (entProvider.HasFinder())
                {
                    _viewProvider = entProvider.GetFinderView();
                }
                if (_viewProvider == null)
                {
                    this.Title = string.Format(Resource.TITLE_WRAPPER_DEFAULT); 
                    return;
                }
                _isConnectedAsConsumer = true;
                Title = string.Format(Resource.TITLE_WRAPPER_FOR, _providerName, (string.IsNullOrEmpty(_parameterName))?string.Empty: _parameterName.ToUpper());
                
                PersistedView = Utility.GetXml(_viewProvider);
                //SaveProperty();
                
                // Now we have view, let's ask entity instance. 
                // NB! View cannot be null!
                IEntityInstance instProvider = provider.GetEntityInstance(_viewProvider);
                if (instProvider == null)
                {
                    return;
                }

                // Let's ask entity as data table.
                _tableProvider = instProvider.EntityAsDataTable;
                if (_tableProvider == null) return;
                UserView = Utility.GetXml(_tableProvider);
                //SaveProperty(System.Web.UI.WebControls.WebParts.PersonalizationScope.User, new EventHandler(SaveUserView));
            
                
                // Check if data table has rows.
                if (_tableProvider.Rows.Count == 0) return;
                _rowProvider = _tableProvider.Rows[0];

                //// Everything is okay, let's save filter value;
                //this.serviceCaseId = dt.Rows[0][this.filterField].ToString();
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
            }
        }
        
        private void SaveUserView(object sender, EventArgs e)
        {
            UserView = Utility.GetXml(_tableProvider);
            AspWebParts.WebPart.SetPersonalizationDirty(this);
        }
        #endregion

        #region Provider members

        public void GetRowData(System.Web.UI.WebControls.WebParts.RowCallback callback)
        {
            DataRowView rowView = GetFieldDataRow();
            try
            {
                callback(rowView);
                AspWebParts.WebPart consumer = callback.Target as AspWebParts.WebPart;
                _consumerName = consumer.Title;
                _isConnectedAsProvider = true;
            }
            catch (Exception ex)
            {
                Controls.Add(new LiteralControl("<BR>")); 
                Controls.Add(new LiteralControl(ex.Message));
                Controls.Add(new LiteralControl("<BR>"));
            }
        }

        public System.ComponentModel.PropertyDescriptorCollection Schema
        {
            get
            {
                DataRowView rowView = GetFieldDataRow();
                return System.ComponentModel.TypeDescriptor.GetProperties(rowView);
            }
        }

        [AspWebParts.ConnectionProvider("BDC Data Row", "BDCProvider")]
        public AspWebParts.IWebPartRow GetConnectionInterface()
        {
            return this;
        }

        #endregion

        #region Private methods

        private DataTable GetFieldDataTable()
        {
            if (this.Page == null)
            {
                SPWeb web = new SPSite(HttpContext.Current.Request.Url.AbsoluteUri).OpenWeb();
                string pageUrl = string.Empty;
                if (HttpContext.Current.Request.QueryString != null && HttpContext.Current.Request.QueryString.HasKeys())
                {
                    pageUrl = HttpContext.Current.Request.QueryString["pageUrl"];
                }
                else
                {
                    pageUrl = HttpContext.Current.Request.Url.AbsoluteUri;
                }

                using (SPWebParts.SPLimitedWebPartManager wm = web.GetLimitedWebPartManager(pageUrl, System.Web.UI.WebControls.WebParts.PersonalizationScope.User))
                {
                    AspWebParts.WebPart wp = wm.WebParts[this.ID] as BDCWrapper;
                    {
                        if (wp != null)
                        {
                            BDCWrapper wpTmp = (BDCWrapper)wp;
                            string userView = wpTmp.UserView;
                            if (string.IsNullOrEmpty(userView)) goto SHARED;
                            DataTable table = Utility.GetTable(userView);
                            return table;
                        }
                    }
                }

SHARED:
                using (SPWebParts.SPLimitedWebPartManager wm = web.GetLimitedWebPartManager(pageUrl, System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
                {
                    AspWebParts.WebPart wp = wm.WebParts[this.ID] as BDCWrapper;
                    {
                        if (wp != null)
                        {
                            BDCWrapper wpTmp = (BDCWrapper)wp;
                            string persistedView = wpTmp.PersistedView;
                            DataTable table = Utility.GetTable(persistedView);
                            return table;
                        }
                    }
                }
                return null;
            }
            else
            {
                string resultView = string.IsNullOrEmpty(UserView) ? PersistedView : UserView;
                DataTable table = Utility.GetTable(resultView);
                return table;
            }
        }

        private DataRowView GetFieldDataRow()
        {
            DataTable table = GetFieldDataTable();
            if (table.DefaultView != null)
                return table.DefaultView[0];
            else
                return null;
        }

        #endregion

        #region ITransformableFilterValues Members
        public bool AllowAllValue
        {
            get { return true; }
        }

        public bool AllowEmptyValue
        {
            get { return true; }
        }

        public bool AllowMultipleValues
        {
            get { return true; }
        }

        [AspWebParts.Personalizable(AspWebParts.PersonalizationScope.Shared)]
        [System.ComponentModel.DefaultValue(null)]
        [AspWebParts.WebBrowsable(true)]
        [System.ComponentModel.Category(Constants.WP_CATEGORYNAME_FILTER)]
        public string ParameterName
        {
            get { return _parameterName; }
            set { _parameterName = value; }
        }

        public System.Collections.ObjectModel.ReadOnlyCollection<string> ParameterValues
        {
            get
            {
                //DataRowView rowView = GetFieldDataRow();
                List<string> values = new List<string>();
                //values.Add(rowView.Row[ParameterName].ToString());
                DataTable table = GetFieldDataTable();
                foreach (DataRow row in table.Rows)
                {
                    string val = row[ParameterName].ToString();
                    if (!values.Contains(val)) values.Add(val);
                }
                _isConnectedAsFilterProvider = true;
                return new ReadOnlyCollection<string>(values);                
            }
        }
        [AspWebParts.ConnectionProvider("BDC Filter", "BDCFilterValues", AllowsMultipleConnections = true)]
        public SPWebParts.ITransformableFilterValues SetConnectionInterface()
        {
            return this;
        }
        #endregion

    }
}
